package com.siashan.unipay4j.wx.complaint;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.siashan.unipay4j.core.IPayConfig;
import com.siashan.unipay4j.core.Result;
import com.siashan.unipay4j.core.TradeStateEnum;
import com.siashan.unipay4j.core.UnipayConst;
import com.siashan.unipay4j.core.pay.IQuery;
import com.siashan.unipay4j.core.pay.PayQueryModel;
import com.siashan.unipay4j.core.pay.PayResponse;
import com.siashan.unipay4j.core.util.EnumUtil;
import com.siashan.unipay4j.core.util.MoneyUtil;
import com.siashan.unipay4j.core.util.RequestUtil;
import com.siashan.unipay4j.core.util.StrUtil;
import com.siashan.unipay4j.wx.AbstractWxPay;
import com.siashan.unipay4j.wx.WxPayVersionEnum;
import com.siashan.unipay4j.wx.model.QueryOrderResult;
import com.siashan.unipay4j.wx.pay.WxTradeStateEnum;
import com.siashan.unipay4j.wx.sdk.WXPayConstants;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;

import javax.servlet.http.HttpServletRequest;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import static org.apache.http.HttpStatus.SC_MULTIPLE_CHOICES;
import static org.apache.http.HttpStatus.SC_OK;

/**
 * 微信支付消费者投诉
 *
 * @author siashan
 * @since v1.0.1
 **/
@Slf4j
public class WxPayComplaint extends AbstractWxPay {

    public WxPayComplaint() {
        super();
    }

    public WxPayComplaint(IPayConfig payConfig) {
        super(payConfig);
    }


    /**
     * 创建消费者投诉回调地址
     *
     * @param model 参数
     * @return 执行结果
     */
    public Result<ComplaintAddNotifyUrlResponse> createNotifications(ComplaintAddNotifyUrlModel model) {
        log.info("WxComplaint::=>创建消费者投诉回调地址请求到达");
        // 如果微信支付平台返回的交易号不为空，优先根据微信支付交易号查询，如果为空则根据平台交易号查询
        WechatPayHttpClientBuilder builder = loadBuilder();
        CloseableHttpClient httpClient = builder.build();
        HttpPost httpPost = initHttpPost(WXPayConstants.V3_PAY_URL_CREATE_COMPLAINT_NOTIFICATIONS, JSON.toJSONString(model));
        try {
            CloseableHttpResponse response = httpClient.execute(httpPost);
            StatusLine statusLine = response.getStatusLine();
            String body = EntityUtils.toString(response.getEntity());
            log.info("WxComplaint::=>创建消费者投诉回调地址 返回报文，{}", body);
            int statusCode = statusLine.getStatusCode();
            if (statusCode >= SC_OK && statusCode < SC_MULTIPLE_CHOICES) {
                ComplaintAddNotifyUrlResponse complaintAddNotifyUrlResponse = null;
                if (StrUtil.isNotEmpty(body)) {
                    complaintAddNotifyUrlResponse = JSON.parseObject(body, ComplaintAddNotifyUrlResponse.class);
                }
                return Result.tradeSuccess(complaintAddNotifyUrlResponse);
            } else {
                JSONObject bodyJson = JSON.parseObject(body);
                String errCode = bodyJson.getString(WXPayConstants.CODE);
                String errCodeDes = bodyJson.getString(WXPayConstants.MESSAGE);
                log.info("WxComplaint::=>创建消费者投诉回调地失败,错误代码{},错误原因{}", errCode, errCodeDes);
                return Result.returnFail(errCode, errCodeDes);
            }
        } catch (Exception e) {
            log.warn("WxComplaint=>创建消费者投诉回调地址时发生异常", e);
            return Result.exception();
        }
    }


    /**
     * 删除消费者投诉回调地址
     *
     * @return 执行结果
     */
    public Result<ComplaintAddNotifyUrlResponse> deleteNotifications() {
        log.info("WxComplaint::=>删除消费者投诉回调地址请求到达");
        // 如果微信支付平台返回的交易号不为空，优先根据微信支付交易号查询，如果为空则根据平台交易号查询
        WechatPayHttpClientBuilder builder = loadBuilder();
        CloseableHttpClient httpClient = builder.build();
        HttpDelete httpDelete = initHttpDelete(WXPayConstants.V3_PAY_URL_CREATE_COMPLAINT_NOTIFICATIONS);
        try {
            CloseableHttpResponse response = httpClient.execute(httpDelete);
            StatusLine statusLine = response.getStatusLine();
            String body = EntityUtils.toString(response.getEntity());
            log.info("WxComplaint::=>删除消费者投诉回调地址 返回报文，{}", body);
            int statusCode = statusLine.getStatusCode();
            if (statusCode >= SC_OK && statusCode < SC_MULTIPLE_CHOICES) {
                return Result.tradeSuccess();
            } else {
                JSONObject bodyJson = JSON.parseObject(body);
                String errCode = bodyJson.getString(WXPayConstants.CODE);
                String errCodeDes = bodyJson.getString(WXPayConstants.MESSAGE);
                log.info("WxComplaint::=>删除消费者投诉回调地失败,错误代码{},错误原因{}", errCode, errCodeDes);
                return Result.returnFail(errCode, errCodeDes);
            }
        } catch (Exception e) {
            log.warn("WxComplaint=>删除消费者投诉回调地址时发生异常", e);
            return Result.exception();
        }
    }


    /**
     * 查询消费者投诉回调地址
     *
     * @return 查询结果
     */
    public Result<ComplaintAddNotifyUrlResponse> queryNotifications() {
        log.info("WxComplaint::=>查询消费者投诉回调地址 请求到达");
        // 如果微信支付平台返回的交易号不为空，优先根据微信支付交易号查询，如果为空则根据平台交易号查询
        WechatPayHttpClientBuilder builder = loadBuilder();
        CloseableHttpClient httpClient = builder.build();
        HttpGet httpGet = getHttpGet(WXPayConstants.V3_PAY_URL_CREATE_COMPLAINT_NOTIFICATIONS);
        try {
            CloseableHttpResponse response = httpClient.execute(httpGet);
            StatusLine statusLine = response.getStatusLine();
            String body = EntityUtils.toString(response.getEntity());
            log.info("WxComplaint::=>查询消费者投诉回调地址 返回报文，{}", body);
            if (statusLine.getStatusCode() >= SC_OK && statusLine.getStatusCode() < SC_MULTIPLE_CHOICES) {
                ComplaintAddNotifyUrlResponse complaintAddNotifyUrlResponse = null;
                if (StrUtil.isNotEmpty(body)) {
                    complaintAddNotifyUrlResponse = JSON.parseObject(body, ComplaintAddNotifyUrlResponse.class);
                }
                return Result.tradeSuccess(complaintAddNotifyUrlResponse);
            } else {
                JSONObject bodyJson = JSON.parseObject(body);
                String errCode = bodyJson.getString(WXPayConstants.CODE);
                String errCodeDes = bodyJson.getString(WXPayConstants.MESSAGE);
                log.info("WxComplaint::=>查询消费者投诉回调地址查询失败,错误代码{},错误原因{}", errCode, errCodeDes);
                return Result.returnFail(errCode, errCodeDes);
            }
        } catch (Exception e) {
            log.warn("WxComplaint=>查询消费者投诉回调地址时发生异常", e);
            return Result.exception();
        }
    }


    /**
     * 消费者投诉回调
     *
     * @param request Request请求
     *
     * @return 回调处理结果
     */
    public Result<ComplaintDetail> notify(HttpServletRequest request) {

        try {
            // 请求头Wechatpay-Nonce
            String nonce = request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_NONCE);
            // 请求头Wechatpay-Timestamp
            String timestamp = request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_TIMESTAMP);
            // 请求头Wechatpay-Signature
            String signature = request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_SIGNATURE);
            // 此处一定要使用微信回调返回的序列号，不能使用商户私有序列号，不然会验签失败
            String serialNumber =request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_SERIAL);
            String body = RequestUtil.getStrFromInputSteam(request.getInputStream());
            // 构建request，传入必要参数
            NotificationRequest notificationRequest = new NotificationRequest.Builder().withSerialNumber(serialNumber)
                    .withNonce(nonce)
                    .withTimestamp(timestamp)
                    .withSignature(signature)
                    .withBody(body)
                    .build();
            NotificationHandler handler = new NotificationHandler(loadVerifier(), wxPayConfig.getV3Key().getBytes(StandardCharsets.UTF_8));
            // 验签和解析请求体
            Notification notification = handler.parse(notificationRequest);
            log.info("WxComplaint Notify::=> 回调通知报文：{}",notification.toString());
            return  Result.tradeSuccess(JSON.parseObject(notification.getDecryptData(), ComplaintDetail.class));
        } catch (Exception e) {
            log.warn("WxComplaint Notify::=> 回调时发生异常", e);
        }
        return Result.exception();
    }

    private HttpGet getHttpGet(String url) {
        HttpGet httpGet = new HttpGet(url);
        httpGet.addHeader("Accept", "application/json");
        return httpGet;
    }



    /**
     * 初始化V3 HttpDelete
     *
     * @param url   请求地址
     * @return      HttpDelete对象
     */
    protected HttpDelete initHttpDelete(String url){
        HttpDelete httpDelete = new HttpDelete(url);
        httpDelete.addHeader("Accept", "application/json");
        return httpDelete;
    }
}
